#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <dlfcn.h>
#include <scene.h>
#include <plugin.h>
#include "sdr.h"

struct shader {
	char *name;
	void *so;

	vec4_t (*shade)(ray_t, struct isect_point*, struct material*, struct scene*);
};

struct shader *sdr_create(void)
{
	struct shader *sdr;

	if(!(sdr = malloc(sizeof *sdr))) {
		return 0;
	}
	memset(sdr, 0, sizeof *sdr);
	return sdr;
}

void sdr_free(struct shader *sdr)
{
	if(sdr->so) {
		dlclose(sdr->so);
	}
	free(sdr->name);
	free(sdr);
}

int sdr_load(struct shader *sdr, const char *name)
{
	void (*pinfo)(FILE*);

	sdr_set_name(sdr, name);
	if(!(sdr->so = get_plugin(name))) {
		fprintf(stderr, "missing shader plugin: %s\n", name);
		return -1;
	}

	fprintf(stderr, "Loading: ");
	if((pinfo = dlsym(sdr->so, "plugin_info"))) {
		pinfo(stderr);
	} else {
		fprintf(stderr, "%s plugin (shader)\n", name);
	}

	if(!(sdr->shade = dlsym(sdr->so, "shade"))) {
		fprintf(stderr, "shader plugin \"%s\" doesn't provide a \"shade\" function\n", name);
		dlclose(sdr->so);
		return -1;
	}
	return 0;
}

int sdr_set_name(struct shader *sdr, const char *name)
{
	char *tmp;

	if(!(tmp = malloc(strlen(name) + 1))) {
		return -1;
	}
	strcpy(tmp, name);

	free(sdr->name);
	sdr->name = tmp;
	return 0;
}

const char *sdr_get_name(struct shader *sdr)
{
	return sdr->name;
}

vec4_t sdr_shade(struct shader *sdr, ray_t ray, struct isect_point *is,
		struct material *mat, struct scene *scn)
{
	assert(sdr->shade);
	return sdr->shade(ray, is, mat, scn);
}
